#include "stdafx.h"
#include "BigInt.h"

using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
using namespace APIAL;

namespace BigIntUnitTest
{
	[TestClass]
	public ref class DivideUnitTest
	{
	private:
		TestContext^ testContextInstance;
		static BigInt *op1;
		static BigInt *op2;
		static BigInt *scratch1;
		static BigInt *result1;
		static BigInt *result2;
		static BigInt *expected;

	public: 
		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		property Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ TestContext
		{
			Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get()
			{
				return testContextInstance;
			}
			System::Void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ value)
			{
				testContextInstance = value;
			}
		};

		#pragma region Additional test attributes
		//
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		[ClassInitialize()]
		static void MyClassInitialize(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ testContext) {
			op1 = new BigInt(3, 8);
			op2 = new BigInt(3, 8);
			result1 = new BigInt(3, 8);
			result2 = new BigInt(3, 8);
			scratch1 = new BigInt(3, 8);
			expected = new BigInt(3, 8);
		}
		//
		//Use ClassCleanup to run code after all tests in a class have run
		[ClassCleanup()]
		static void MyClassCleanup() { 
			delete op1;
			delete op2;
			delete result1;
			delete result2;
			delete scratch1;
			delete expected;
		}
		//
		//Use TestInitialize to run code before running each test
		//[TestInitialize()]
		//void MyTestInitialize() {};
		//
		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//void MyTestCleanup() {};
		//
		#pragma endregion 

		[TestMethod]
		void OneChunkDivide()
		{

			// divide 120 / 13 = 9
			op1->ParseHexadecimalString("78", true);	// 120
			op2->ParseHexadecimalString("D", true);		// 13

			result1->chunks[0] = 0;
			result1->size = 0;

			result2->ParseHexadecimalString("9", true);	// 9

			Divide(op1, op2, result1);
			BigInt::normalize(*result1);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<int>(1, result1->size);
		};

		[TestMethod]
		void OneChunkDivideTwo()
		{
			// divide 111 / 2 = 55
			op1->ParseHexadecimalString("6F", true);	// 111
			op2->ParseHexadecimalString("2", true);		// 12

			result1->chunks[0] = 0;
			result1->size = 0;

			result2->ParseHexadecimalString("37", true);	// 55

			Divide(op1, op2, result1);
			BigInt::normalize(*result1);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<int>(1, result1->size);
		};

		[TestMethod]
		void OneChunkDivideByOne()
		{
			// divide 120 / 13 = 9
			op1->ParseHexadecimalString("6A", true);	// 7
			op2->ParseHexadecimalString("1", true);		// 1

			result1->chunks[0] = 0;
			result1->size = 0;

			result2->ParseHexadecimalString("6A", true);	// 7

			Divide(op1, op2, result1);
			BigInt::normalize(*result1);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<int>(1, result1->size);
		};

		[TestMethod]
		void TwoChunkDivideByOne()
		{
			// divide 1974 / 1 = 1974
			op1->ParseHexadecimalString("7B6", true);	// 1974
			op2->ParseHexadecimalString("1", true);		// 1

			result1->chunks[0] = 0;
			result1->size = 0;

			result2->ParseHexadecimalString("7B6", true);	// 1974

			Divide(op1, op2, result1);
			BigInt::normalize(*result1);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<int>(2, result1->size);
		};

		[TestMethod]
		void TwoChunkDivideComplex()
		{
			// divide 1899 / 67 = 28
			op1->ParseHexadecimalString("76B", true);	// 1899
			op2->ParseHexadecimalString("43", true);	// 67

			result1->chunks[0] = 0;
			result1->size = 0;

			result2->ParseHexadecimalString("1C", true);	// 28

			Divide(op1, op2, result1);
			BigInt::normalize(*result1);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<int>(1, result1->size);
		};

		[TestMethod]
		void ThreeChunkDivide()
		{
			// divide 19915 / 113 = 169
			op1->ParseHexadecimalString("4AAB", true);	// 1899
			op2->ParseHexadecimalString("71", true);	// 113

			result1->chunks[0] = 0;
			result1->size = 0;

			result2->ParseHexadecimalString("A9", true);	// 169

			Divide(op1, op2, result1);
			BigInt::normalize(*result1);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<BigInt::chunkType>(result2->chunks[0], result1->chunks[0]);
			Assert::AreEqual<int>(2, result1->size);
		};

		[TestMethod]
		void TestDivideDifferingSign() {
			op1->ParseHexadecimalString("F9823ABC1359829", true);
			op2->ParseHexadecimalString("23876565", true);
			expected->ParseHexadecimalString("705CF9B0", true);

			// Pos/pos
			APIAL::Divide(op1, op2, result1);
			Assert::IsTrue(op1->positive);
			Assert::IsTrue(op2->positive);
			Assert::IsTrue(Equal(result1, expected));

			// Neg/neg
			op1->positive = false;
			op2->positive = false;
			APIAL::Divide(op1, op2, result1);
			Assert::IsFalse(op1->positive);
			Assert::IsFalse(op2->positive);
			Assert::IsTrue(result1->positive);
			Assert::IsTrue(Equal(result1, expected));

			// Pos/neg
			op1->positive = true;
			op2->positive = false;
			expected->positive = false;
			APIAL::Divide(op1, op2, result1);
			Assert::IsTrue(op1->positive);
			Assert::IsFalse(op2->positive);
			Assert::IsFalse(result1->positive);
			Assert::IsTrue(Equal(result1, expected));

			// Neg/pos
			op1->positive = false;
			op2->positive = true;
			APIAL::Divide(op1, op2, result1);
			Assert::IsFalse(op1->positive);
			Assert::IsTrue(op2->positive);
			Assert::IsFalse(result1->positive);
			Assert::IsTrue(Equal(result1, expected));
		}
	};
}
